/*
 * Sylvain BERTRAND <digital.ragnarok@gmail.com>
 * code protected by GNU GPL v3
 */
#include <X11/Xlib.h>
#include <glib.h>
#include <libxml/xinclude.h>
#include "../../toolkit/keyboard.h"
#include "../../toolkit/xml.h"
#include "../misc.h"
#include "../geom.h"
#include "../frame.h"
#include "../actions.h"
#include "../window.h"
#include "../stacking.h"
#include "../client.h"
struct options {
	enum wm_direction dir;
	gboolean shrink;
};

static gpointer setup_func(xmlNodePtr node)
{
	xmlNodePtr n;
	struct options *o;
	o = g_slice_new0(struct options);
	o->dir = WM_DIRECTION_NORTH;
	o->shrink = FALSE;
	if((n = t_xml_find_node(node, "direction"))) {
		gchar *s = t_xml_node_string(n);
		if(!g_ascii_strcasecmp(s, "north") || !g_ascii_strcasecmp(s, "up"))
			o->dir = WM_DIRECTION_NORTH;
		else if(!g_ascii_strcasecmp(s, "south") || !g_ascii_strcasecmp(s, "down"))
			o->dir = WM_DIRECTION_SOUTH;
		else if(!g_ascii_strcasecmp(s, "west") || !g_ascii_strcasecmp(s, "left"))
			o->dir = WM_DIRECTION_WEST;
		else if(!g_ascii_strcasecmp(s, "east") || !g_ascii_strcasecmp(s, "right"))
			o->dir = WM_DIRECTION_EAST;
		g_free(s);
	}
	return o;
}

static gpointer setup_shrink_func(xmlNodePtr node)
{
	struct options *o;
	o = setup_func(node);
	o->shrink = TRUE;
	return o;
}

static gboolean do_grow(struct wm_actions_data *data, gint x, gint y, gint w, gint h)
{
	gint realw, realh, lw, lh;
	realw = w;
	realh = h;
	client_try_configure(data->client, &x, &y, &realw, &realh, &lw, &lh, TRUE);
	if(x != data->client->area.x)
		x += w - realw;
	if(y != data->client->area.y)
		y += h - realh;
	if(x != data->client->area.x || y != data->client->area.y || realw != data->client->area.width
		|| realh != data->client->area.height) {
		actions_client_move(data, TRUE);
		client_move_resize(data->client, x, y, realw, realh);
		actions_client_move(data, FALSE);
		return TRUE;
	}
	return FALSE;
}

static void free_func(gpointer o)
{
	g_slice_free(struct options, o);
}

static gboolean run_func(struct wm_actions_data *data, gpointer options)
{
	struct options *o = options;
	gint x, y, w, h;
	enum wm_direction opp;
	gint half;
	if(!data->client) {
		return FALSE;
	}
	if(!o->shrink) {
		client_find_resize_directional(data->client, o->dir, TRUE, &x, &y, &w, &h);
		if(do_grow(data, x, y, w, h))
			return FALSE;
	}
	opp =
		(o->dir == WM_DIRECTION_NORTH ? WM_DIRECTION_SOUTH : (o->dir ==
			WM_DIRECTION_SOUTH ? WM_DIRECTION_NORTH : (o->dir ==
				WM_DIRECTION_EAST ? WM_DIRECTION_WEST : WM_DIRECTION_EAST)));
	client_find_resize_directional(data->client, opp, FALSE, &x, &y, &w, &h);
	switch (opp) {
	case WM_DIRECTION_NORTH:
		half = data->client->area.y + data->client->area.height / 2;
		if(y > half) {
			h += y - half;
			y = half;
		}
		break;
	case WM_DIRECTION_SOUTH:
		half = data->client->area.height / 2;
		if(h < half)
			h = half;
		break;
	case WM_DIRECTION_WEST:
		half = data->client->area.x + data->client->area.width / 2;
		if(x > half) {
			w += x - half;
			x = half;
		}
		break;
	case WM_DIRECTION_EAST:
		half = data->client->area.width / 2;
		if(w < half)
			w = half;
		break;
	default:
		g_assert_not_reached();
	}
	if(do_grow(data, x, y, w, h))
		return FALSE;
	return FALSE;
}

static gpointer setup_north_func(xmlNodePtr node)
{
	struct options *o = g_slice_new0(struct options);
	(void)node;
	o->shrink = FALSE;
	o->dir = WM_DIRECTION_NORTH;
	return o;
}

static gpointer setup_south_func(xmlNodePtr node)
{
	struct options *o = g_slice_new0(struct options);
	(void)node;
	o->shrink = FALSE;
	o->dir = WM_DIRECTION_SOUTH;
	return o;
}

static gpointer setup_east_func(xmlNodePtr node)
{
	struct options *o = g_slice_new0(struct options);
	(void)node;
	o->shrink = FALSE;
	o->dir = WM_DIRECTION_EAST;
	return o;
}

static gpointer setup_west_func(xmlNodePtr node)
{
	struct options *o = g_slice_new0(struct options);
	(void)node;
	o->shrink = FALSE;
	o->dir = WM_DIRECTION_WEST;
	return o;
}

void action_growtoedge_startup(void)
{
	actions_register("GrowToEdge", setup_func, free_func, run_func);
	actions_register("ShrinkToEdge", setup_shrink_func, free_func, run_func);
	actions_register("GrowToEdgeNorth", setup_north_func, free_func, run_func);
	actions_register("GrowToEdgeSouth", setup_south_func, free_func, run_func);
	actions_register("GrowToEdgeEast", setup_east_func, free_func, run_func);
	actions_register("GrowToEdgeWest", setup_west_func, free_func, run_func);
}
